#pragma once
#include <sys/poll.h>
#include <string>
#include <iostream>
#include "Sock.hpp"
#include "Log.hpp"

const static uint16_t DEFAULTPORT = 8888;
const static int N = 4096;
const static int DEFAULTFD = -1;
const static short DEFAULTEVENT = 0;

class pollServer
{
public:
    pollServer(uint16_t port = DEFAULTPORT) : _port(port), _fdarray(nullptr)
    {
    }
    ~pollServer()
    {
        _listen_sock.Close();
        if (_fdarray)
            delete[] _fdarray;
    }
    void InitServer()
    {
        _listen_sock.Socket();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();

        // 为pollfd[]数组分配空间并初始化
        _fdarray = new pollfd[N];
        for (int i = 0; i < N; ++i)
        {
            _fdarray[i].fd = DEFAULTFD;
            _fdarray[i].events = DEFAULTEVENT;
            _fdarray[i].revents = DEFAULTEVENT;
        }
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;
        int sock = _listen_sock.Accept(&clientip, &clientport);
        if (sock < 0)
            return;
        logMessage(Debug, "[%s:%d], sock: %d", clientip.c_str(), clientport, sock);
        int pos = 1;
        for (; pos < N; pos++)
        {
            if (_fdarray[pos].fd == DEFAULTFD)
                break;
        }
        if (pos >= N) // ...可以动态扩容
        {
            close(sock);
            logMessage(Warning, "sockfd array[] full");
        }
        else
        {
            _fdarray[pos].fd = sock;
            _fdarray[pos].events = POLLIN; // (POLLIN|POLLOUT)
            _fdarray[pos].revents = DEFAULTEVENT;
        }
    }
    void Recver(int fd, int i)
    {
        char buffer[1024];
        ssize_t s = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << "client# " << buffer << std::endl;
            // fdarray_[i].events |= POLLOUT;

            std::string echo = "[select server echo]";
            echo += buffer;
            send(fd, echo.c_str(), echo.size(), 0);
        }
        else
        {
            if (s == 0)
                logMessage(Info, "client quit ..., fdarray_[i] -> defaultfd: %d->%d", fd, defaultfd);
            else
                logMessage(Warning, "recv error, client quit ..., fdarray_[i] -> defaultfd: %d->%d", fd, defaultfd);
            close(fd);

            _fdarray[i].fd = DEFAULTFD;
            _fdarray[i].events = DEFAULTEVENT;
            _fdarray[i].revents = DEFAULTEVENT;
        }
    }
    void HandleEvent()
    {
        // 扫描_fdarray处理所有就绪的文件描述符
        for (int i = 0; i < N; ++i)
        {
            int fd = _fdarray[i].fd;
            short revent = _fdarray[i].revents;
            if (fd == DEFAULTFD)
                continue;
            // 读事件就绪
            if (revent & POLLIN)
            {
                if (fd == _listen_sock.Fd())
                    Accepter(); // 监听套接字读事件就绪
                else
                    Recver(fd, i); // IO套接字读事件就绪
            }
            // 写事件就绪
            else if (revent & POLLOUT)
            {
                // ...
            }
            // else if() // xx事件就绪...
            // {

            // }
        }
    }
    void Start()
    {
        _fdarray[0].fd = _listen_sock.Fd();
        _fdarray[0].events = POLLIN; // 等待监听套接字的读事件
        while (true)
        {
            int timeout = -1; // 阻塞式等待
            int n = poll(_fdarray, N, timeout);
            switch (n)
            {
            case 0:
                logMessage(Debug, "Time out, %d: %s", errno, strerror(errno));
                break;
            case -1:
                logMessage(Fatal, "%d: %s", errno, strerror(errno));
                break;
            default:
                logMessage(Debug, "有一个就绪事件发生了: %d", n);
                HandleEvent();
                DebugPrint();
                break;
            }
            sleep(1);
        }
    }
    void DebugPrint()
    {
        std::cout << "_fdarray[]: ";
        for (int i = 0; i < N; ++i)
            if (_fdarray[i].fd != DEFAULTFD)
                std::cout << _fdarray[i].fd << " ";
        std::cout << "\n";
    }

private:
    uint16_t _port;
    Sock _listen_sock;
    struct pollfd *_fdarray;
};